package com.personal.core.exchange;

import java.util.HashMap;
import java.util.Map;

import com.personal.core.exchange.decimal.BigDecimalDoubleConvertor;
import com.personal.core.exchange.decimal.BigDecimalIntConvertor;
import com.personal.core.exchange.decimal.BigDecimalLongConvertor;
import com.personal.core.exchange.decimal.BigDecimalSqlDateConvertor;
import com.personal.core.exchange.decimal.BigDecimalStrConvertor;
import com.personal.core.exchange.decimal.BigDecimalTimeConvertor;
import com.personal.core.exchange.decimal.BigDecimalUtilDateConvertor;
import com.personal.core.exchange.doubletype.DoubleBigDecimalConvertor;
import com.personal.core.exchange.doubletype.DoubleDateConvertor;
import com.personal.core.exchange.doubletype.DoubleIntConvertor;
import com.personal.core.exchange.doubletype.DoubleLongConvertor;
import com.personal.core.exchange.doubletype.DoubleSqlDateConvertor;
import com.personal.core.exchange.doubletype.DoubleStrConvertor;
import com.personal.core.exchange.doubletype.DoubleTimeConvertor;
import com.personal.core.exchange.integer.IntBigDecimalConvertor;
import com.personal.core.exchange.integer.IntDateConvertor;
import com.personal.core.exchange.integer.IntDoubleConvertor;
import com.personal.core.exchange.integer.IntLongConvertor;
import com.personal.core.exchange.integer.IntSqlDateConvertor;
import com.personal.core.exchange.integer.IntStrConvertor;
import com.personal.core.exchange.integer.IntTimeConvertor;
import com.personal.core.exchange.jdbc.BlobByteConvertor;
import com.personal.core.exchange.jdbc.BlobStrConvertor;
import com.personal.core.exchange.jdbc.ByteBlobConvertor;
import com.personal.core.exchange.jdbc.ClobStrConvertor;
import com.personal.core.exchange.jdbc.StrBlobConvertor;
import com.personal.core.exchange.jdbc.StrClobConvertor;
import com.personal.core.exchange.longtype.LongBigDecimalConvertor;
import com.personal.core.exchange.longtype.LongDateConvertor;
import com.personal.core.exchange.longtype.LongDoubleConvertor;
import com.personal.core.exchange.longtype.LongIntConvertor;
import com.personal.core.exchange.longtype.LongSqlDateConvertor;
import com.personal.core.exchange.longtype.LongStrConvertor;
import com.personal.core.exchange.longtype.LongTimeConvertor;
import com.personal.core.exchange.sqldate.SqlDateLongConvertor;
import com.personal.core.exchange.sqldate.SqlDateStrConvertor;
import com.personal.core.exchange.sqldate.SqlDateTimeConvertor;
import com.personal.core.exchange.sqldate.SqlDateUtilDateConvertor;
import com.personal.core.exchange.string.StrBigDecmialConvertor;
import com.personal.core.exchange.string.StrDateConvertor;
import com.personal.core.exchange.string.StrDoubleConvertor;
import com.personal.core.exchange.string.StrIntConvertor;
import com.personal.core.exchange.string.StrLongConvertor;
import com.personal.core.exchange.string.StrSqlDateConvertor;
import com.personal.core.exchange.string.StrTimeConvertor;
import com.personal.core.exchange.time.TimeLongConvertor;
import com.personal.core.exchange.time.TimeSqlDateConvertor;
import com.personal.core.exchange.time.TimeStrConvertor;
import com.personal.core.exchange.time.TimeUtilDateConvertor;
import com.personal.core.exchange.utildate.UtilDateLongConvertor;
import com.personal.core.exchange.utildate.UtilDateSqlDateConvertor;
import com.personal.core.exchange.utildate.UtilDateStrConvertor;
import com.personal.core.exchange.utildate.UtilDateTimeConvertor;

public class ConvertFactory
{
  private Map<Class<?>, Map<Class<?>, Convertor<?, ?>>> ConvertorMap = new HashMap<>();

  private static final Class<?>[] CONVETOR_CLASSES = { BigDecimalDoubleConvertor.class, BigDecimalIntConvertor.class, BigDecimalLongConvertor.class, BigDecimalSqlDateConvertor.class, BigDecimalStrConvertor.class, BigDecimalTimeConvertor.class, BigDecimalUtilDateConvertor.class, DoubleBigDecimalConvertor.class, DoubleDateConvertor.class, DoubleIntConvertor.class, DoubleLongConvertor.class, DoubleSqlDateConvertor.class, DoubleStrConvertor.class, DoubleTimeConvertor.class, IntBigDecimalConvertor.class, IntDateConvertor.class, IntDoubleConvertor.class, IntLongConvertor.class, IntSqlDateConvertor.class, IntStrConvertor.class, IntTimeConvertor.class, BlobByteConvertor.class, BlobStrConvertor.class, ByteBlobConvertor.class, ClobStrConvertor.class, StrBlobConvertor.class, StrClobConvertor.class, LongBigDecimalConvertor.class, LongDateConvertor.class, LongDoubleConvertor.class, LongIntConvertor.class, LongSqlDateConvertor.class, LongStrConvertor.class, LongTimeConvertor.class, SqlDateLongConvertor.class, SqlDateStrConvertor.class, SqlDateTimeConvertor.class, SqlDateUtilDateConvertor.class, StrBigDecmialConvertor.class, StrDateConvertor.class, StrDoubleConvertor.class, StrIntConvertor.class, StrLongConvertor.class, StrSqlDateConvertor.class, StrTimeConvertor.class, TimeLongConvertor.class, TimeSqlDateConvertor.class, TimeStrConvertor.class, TimeUtilDateConvertor.class, UtilDateLongConvertor.class, UtilDateSqlDateConvertor.class, UtilDateStrConvertor.class, UtilDateTimeConvertor.class};

  private static ConvertFactory factory = new ConvertFactory();

  private ConvertFactory()
  {
    for (Class clazz : CONVETOR_CLASSES)
    {
      try
      {
        Convertor convertor = (Convertor)clazz.newInstance();
        addConvertor(convertor);
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public static ConvertFactory getFactory()
  {
    return factory;
  }

  public void addConvertor(Convertor<?, ?> convertor)
  {
    if (convertor == null)
    {
      return;
    }

    ConvertionClassInfo classInfo = convertor.getClassInfo();

    if ((classInfo == null) || (classInfo.getOrginalClass() == null) || (classInfo.getTransformClass() == null))
    {
      return;
    }

    Map map = (Map)this.ConvertorMap.get(classInfo.getOrginalClass());

    if (map == null)
    {
      map = new HashMap();
      this.ConvertorMap.put(classInfo.getOrginalClass(), map);
    }

    map.put(classInfo.getTransformClass(), convertor);
  }

  public <T> T exchange(Object value, Class<T> tranformClass, T defaultValue)
  {
    if ((value == null) || (tranformClass == null))
    {
      return defaultValue;
    }

    if (value.getClass() == tranformClass)
    {
      return (T) value;
    }

    Convertor convertor = getConvertor(value.getClass(), tranformClass);

    if (convertor == null)
    {
      return defaultValue;
    }

    Object trObj = convertor.exchangeType(value);
    return trObj == null ? defaultValue : (T) trObj;
  }

  public Object exchange(Object value, Class<?> tranformClass)
  {
    if ((value == null) || (tranformClass == null))
    {
      return null;
    }

    if (value.getClass() == tranformClass)
    {
      return value;
    }

    Convertor convertor = getConvertor(value.getClass(), tranformClass);

    if (convertor == null)
    {
      return value;
    }

    return convertor.exchangeType(value);
  }

  public Convertor<?, ?> getConvertor(Class<?> orginalClass, Class<?> tranformClass)
  {
    Map map = (Map)this.ConvertorMap.get(orginalClass);

    if (map == null)
    {
      return null;
    }

    return (Convertor)map.get(tranformClass);
  }
}